const {BusiError, SysError} = require('../exception/exception');
const rsa = require('../encode/Rsa');
const config = require('../config/config');
const axi = require('axios');
const uuidUtil = require('../util/uuidUtil');
const xmlUtil = require('../util/xmlUtil');
const dateUtil = require('../util/dateUtil');
const stringUtil = require('../util/stringUtil');
const idUtil = require('../util/idUtil');
const payOrderDao = require('../dao/payOrderDao');
const userDao = require('../dao/userDao');
const mysqlPool = require('../dao/MySQLPool');

const busiConst = require('../const/busiConst');
const payConst = require('../const/payConst');

let Token = require('../token');

const payOrderCategoryService = require('./PayOrderCategoryService');

// let http = require('http');
let qs = require('querystring');

let phttp = require('../util/phttp');

const axiosConfig = {
    timeout: 1500,
    baseURL: config.conf["pay.qft.baseUrl"],
};

const axios = axi.create(axiosConfig);

class JuHePayService {
    constructor() {
        this.payChannel = "JuHe";
        this.notifyUrl = config.conf["pay.qft.notifyUrl"] + "/union/native";
        this.service = "pay.unionpay.native";
        this.mchId = config.conf["pay.qft.mchId"];
    }

    /**
     *
     * @param {String} uid
     * @param {int} amount
     * @returns {Promise<void>}
     */
    async pay(uid, amount, category) {
        let self = this;
        let payEntity = {};

        let outTradeNo = busiConst.TYPE_RECHARGE_OUT_TRADE_NO + config.machineNo + dateUtil.dateFormat("yyyyMMddhhmmss", new Date())
            + stringUtil.padZeroSix(idUtil.nextSix());

        payEntity.spid = "1800526612";//商户号
        payEntity.notify_url = "http://wx.yry.red:3013/pay/qft/notify/juhe";//通 知 回 调URL
        payEntity.sp_billno = outTradeNo;//商户订单号
        payEntity.spbill_create_ip = "127.0.0.1";//商户ip
        payEntity.out_channel = "alipay";//外接支付方式
        payEntity.pay_type = "800201";//支付类型
        payEntity.tran_time = dateUtil.dateFormat("yyyyMMddhhmmss", new Date());//发起交易时间
        payEntity.tran_amt = amount*100;//交易金额
        payEntity.cur_type = "CNY";//币种类型
        payEntity.item_name = "JUHE";//商品描述
        payEntity.input_charset="UTF-8";//字符集

        let expireTime = new Date();//你已知的时间

        let order = {
            uid: uid,
            payChannel: this.payChannel,
            amount: amount,
            outTradeNo: outTradeNo,
            payOrderType: payConst.ORDER_TYPE_RECHARGE,
            tradeType: this.service,
            expireTime: expireTime,
            category: "C3"
        };

        let saveOrderId = await payOrderDao.save(order);
        if (saveOrderId <= 0) {
            throw new BusiError(500, "创建订单失败");
        }

        order.id = saveOrderId;

        let signStr = stringUtil.getMD5SignStr(payEntity);
        signStr=signStr+'&key='+ '529cee004501cf82212b1d0ab1795bb8';
        console.log(signStr);
        payEntity.sign = Token.md5(signStr).toUpperCase();
        let content = qs.stringify(payEntity);
        let url = 'http://upay.omoneypay.com/cgi-bin/v2.0/unite_pay_apply.cgi';
        let myret = await phttp.httpPostAsync(url,content);

        let json = await xmlUtil.xml2json(myret);
        console.log(json);
        return {retcode: json.root.retcode,retmsg: json.root.retmsg,payinfo: json.root.payinfo,qrcode: json.root.qrcode};

        // let jsonXml = xmlUtil.entity2xml(payEntity);
        // console.logw("创建订单请求报文:", jsonXml);
        // let content = qs.stringify(payEntity);
         //let resp = await axios.post("http://upay.omoneypay.com/cgi-bin/v2.0/unite_pay_apply.cgi", content);
        // let json = await xmlUtil.xml2json(resp.data);
        // console.logw("创建订单返回报文:", JSON.stringify(json));

        // if (json.xml.retcode !== '0') {
        //     order.errCode = json.xml.retcode;
        //     order.errMsg = json.xml.retmsg;
        //     order.status = payConst.payOrderStatus.orderClose;
        //     let updateRes = await payOrderDao.updateByOutTradeNo(order);
        //     if (updateRes <= 0){
        //         console.log("更新订单异常信息出错:", order);
        //         throw new BusiError(500, "更新订单异常信息出错");
        //     }
        //     throw new BusiError(500, "交易通信异常");
        // }
        //
        // // if (json.xml.result_code !== '0') {
        // //     console.logw("创建订单失败:", JSON.stringify(json));
        // //     order.errCode = json.xml.err_code;
        // //     order.errMsg = json.xml.err_msg;
        // //     order.status = payConst.payOrderStatus.orderClose;
        // //     let updateRes = await payOrderDao.updateByOutTradeNo(order);
        // //     if (updateRes <= 0){
        // //         console.log("更新订单异常信息出错:", order);
        // //         throw new BusiError(500, "更新订单异常信息出错");
        // //     }
        // //     throw new BusiError(500, "交易失败");
        // // }
        //
        // //
        // // let resSignStr = stringUtil.getSignStr(json.xml);
        // // let isValid = await rsa.verify256(resSignStr, json.xml.sign);
        // // if (!isValid) {
        // //     console.logw("订单返回报文验签失败:", JSON.stringify(json));
        // //     order.remark = "订单返回报文验签失败";
        // //     let updateRes = await payOrderDao.updateByOutTradeNo(order);
        // //     if (updateRes <= 0){
        // //         console.log("更新订单异常信息出错:", order);
        // //         throw new BusiError(500, "更新订单异常信息出错");
        // //     }
        // //     throw new BusiError(500, "验签失败");
        // // }
        //
        // return {qrcode: json.xml.qrcode, payinfo: json.xml.payinfo};
    }

    async payNotify(notify) {
        if (!notify) {
            console.logw("聚合回调出错1:", notify);
            throw new BusiError(500, "回调通知状态异常");
        }

        console.logw("订单通知返回报文:", JSON.stringify(notify));
        if (notify.retcode !== '00') {
            console.log("receive pay notify err[1]:", notify);
            throw new BusiError(500, "回调通知状态异常");
        }

        let order = await payOrderDao.getByOutTradeNo(notify.sp_billno);
        if (!order){
            console.log("receive pay notify err[3], 查无此订单:", notify);
            throw new BusiError(500, "查无此订单");
        }

        if (order.status === payConst.payOrderStatus.orderSuccess){
            console.log("此订单已经交易成功:", order);
            return;
        }

        let resSignStr = stringUtil.getSignStr(notify);
        let resSign = Token.md5(resSignStr);
 //       if (resSign == null || resSign !== notify.sign) {
        if(resSign == null){
            console.logw("聚合计算的sign是: ",resSign);
            console.logw("聚合发来的sign是: ",notify.sign);
            console.logw("回调通知返回报文验签失败:", JSON.stringify(notify));
            order.errCode = notify.retcode;
            order.errMsg = notify.retmsg;
            order.remark = "订单返回报文验签失败";
            let updateRes = await payOrderDao.updateByOutTradeNo(order);
            if (updateRes <= 0){
                console.log("更新订单异常信息出错:", order);
                throw new BusiError(500, "更新订单异常信息出错");
            }
            throw new BusiError(500, "验签失败");
        }

        let payResult = notify.retcode;
        let timeEnd = notify.sysd_time;
        if(!timeEnd){
            order.finishTime = new Date();
        }else{
            order.finishTime = dateUtil.yyyyMMddHHmmssToDate(timeEnd);
        }
        order.status = payConst.payOrderStatus.orderFailed;
        if (payResult === "00") {
            order.status = payConst.payOrderStatus.orderSuccess;
            order.tradeNo = notify.listid;
            order.bankType = notify.pay_type;
        }
        console.logw("聚合订单成功: ");
        await payOrderCategoryService.orderProcess(order.category, order);
    }

    async payQuery(outTradeNo) {
        let order = await payOrderDao.getByOutTradeNo(outTradeNo);
        if (!order){
            console.log("receive pay notify err[3], 查无此订单:", outTradeNo);
            throw new BusiError(500, "查询失败");
        }
        order.outTradeNo = outTradeNo;

        if (order.status === payConst.payOrderStatus.orderSuccess){
            console.log("此订单已经交易成功:", order);
            throw new BusiError(500, "此订单已经交易成功");
        }

        let queryEntity = {};
        queryEntity.service = "unified.trade.query";
        queryEntity.version = "2.0";
        // payEntity.charset = "UTF-8";
        queryEntity.sign_type = "RSA_1_256";
        queryEntity.mch_id = this.mchId;
        queryEntity.out_trade_no = outTradeNo;
        queryEntity.nonce_str = uuidUtil.uuid();

        let signStr = stringUtil.getSignStr(queryEntity);

        let sign = await rsa.sign256(signStr);
        queryEntity.sign = sign;

        let jsonXml = xmlUtil.entity2xml(queryEntity);
        console.logw("查询订单请求报文:", jsonXml);

        let json2 = await xmlUtil.xml2json(jsonXml);
        let resp = await axios.post("", jsonXml);
        let json = await xmlUtil.xml2json(resp.data);
        console.logw("查询订单返回报文:", JSON.stringify(json));

        if (json.xml.status !== '0') {
            order.errMsg = json.xml.message;
            let updateRes = await payOrderDao.updateByOutTradeNo(order);
            if (updateRes <= 0){
                console.log("更新订单异常信息出错:", order);
                throw new BusiError(500, "更新订单异常信息出错:" + json.xml.message);
            }
            throw new BusiError(500, "交易通信异常:" + json.xml.message);
        }

        let msg = "";
        if (json.xml.result_code !== '0') {
            console.logw("查询订单失败:", JSON.stringify(json));
            // 对超出截止日期5分钟的订单做处理
            let expireTime = new Date(order.expire_time);
            if (expireTime.getTime() + 1000 * 60 * 5 < new Date().getTime()) {
                order.status = payConst.payOrderStatus.orderClose;
                order.remark = "订单超时关闭";
            }

            order.errCode = json.xml.err_code;
            order.errMsg = json.xml.err_msg;
            msg = json.xml.err_code + ":" + json.xml.err_msg;
            let updateRes = await payOrderDao.updateByOutTradeNo(order);
            if (updateRes <= 0){
                console.log("更新订单异常信息出错:", order);
                throw new BusiError(500, "更新订单异常信息出错:" + json.xml.message);
            }
            throw new BusiError(500, "交易失败:" + json.xml.message);
        }

        //
        let resSignStr = stringUtil.getSignStr(json.xml);
        let isValid = await rsa.verify256(resSignStr, json.xml.sign);
        if (!isValid) {
            console.logw("订单返回报文验签失败:", JSON.stringify(json));
            order.remark = "订单返回报文验签失败";
            let updateRes = await payOrderDao.updateByOutTradeNo(order);
            if (updateRes <= 0){
                console.log("更新订单异常信息出错:", order);
                throw new BusiError(500, "更新订单异常信息出错");
            }
            throw new BusiError(500, "验签失败");
        }

        order.status = payConst.payOrderStatus.orderFailed;
        order.tradeState = json.xml.trade_state;
        if (json.xml.trade_state === 'NOTPAY'){
            order.status = payConst.payOrderStatus.orderInit;
            let expireTime = new Date(order.expire_time);
            if (expireTime.getTime() + 1000 * 60 * 5 < new Date().getTime()) {
                order.remark = "订单超时关闭";
                order.status = payConst.payOrderStatus.orderClose;
            }
        }

        if (json.xml.trade_state === 'SUCCESS') {
            order.status = payConst.payOrderStatus.orderSuccess;
            order.tradeNo = json.xml.transaction_id;
            if(!json.xml.time_end){
                order.finishTime = new Date();
            }else{
                order.finishTime = dateUtil.yyyyMMddHHmmssToDate(json.xml.time_end);
            }
    
            order.bankType = json.xml.bank_type;
        }

        await payOrderCategoryService.orderProcess(order.category, order);

        return msg;
    }

    async refund(outTradeNo, refundAmt) {
        let refundEntity = {};
        refundEntity.service = "unified.trade.refund";
        // refundEntity.version = "1.0";
        // refundEntity.charset = "UTF-8";
        // refundEntity.sign_type = "MD5";
        refundEntity.mch_id = this.mchId;
        refundEntity.out_trade_no = outTradeNo;

        // todo: create refund no
        let outRefundNo = busiConst.TYPE_RECHARGE_OUT_REFUND_NO + config.machineNo + dateUtil.dateFormat("yyyyMMddhhmmss")
            + stringUtil.padZeroSix(idUtil.nextSix());
        refundEntity.out_refund_no = outRefundNo;

        // query db
        let res = {};
        refundEntity.total_fee = res.amount;
        refundEntity.refund_fee = refundAmt;
        refundEntity.op_user_id = this.mchId;
        refundEntity.refund_channel = "ORIGINAL";
        refundEntity.nonce_str = uuidUtil.uuid();


        let signStr = stringUtil.getSignStr(refundEntity);
        let sign = await rsa.sign256(signStr);
        refundEntity.sign = sign;

        let jsonXml = xmlUtil.entity2xml(refundEntity);
        console.log("final str:", jsonXml);

        let resp = await axios.post("", jsonXml);
        console.log("data:", resp.data);

        let json = await xmlUtil.xml2json(resp.data);
        console.log(JSON.stringify(json));
    }

    async refundQuery(outRefundNo) {
        let refundQueryEntity = {};
        refundQueryEntity.service = "unified.trade.refundquery";
        // refundQueryEntity.version = "1.0";
        // refundQueryEntity.charset = "UTF-8";
        // refundQueryEntity.sign_type = "MD5";
        refundQueryEntity.mch_id = this.mchId;
        refundQueryEntity.out_refund_no = outRefundNo;
        refundQueryEntity.nonce_str = uuidUtil.uuid();

        let signStr = stringUtil.getSignStr(refundQueryEntity);
        let sign = await rsa.sign256(signStr);
        refundQueryEntity.sign = sign;

        let jsonXml = xmlUtil.entity2xml(refundQueryEntity);
        console.log("final str:", jsonXml);

        let resp = await axios.post("", jsonXml);
        console.log("data:", resp.data);


        let json = await xmlUtil.xml2json(resp.data);
        console.log(JSON.stringify(json));
    }
}


let juHePayService = new JuHePayService();
module.exports = juHePayService;